﻿using System;
using System.Collections.Generic;
using DimensionsHelper.Common.Utils;

namespace DimensionsHelper.Common.Contracts.DataCollector.Options;

/// <summary>
///     简单的类型表达式，内部使用${}包裹类型名称，
///     ^${}表示不包含类型名，${}标识包含类型名，${}=ID表示类型值等于ID，
///     ^${}=ID表示类型值不等于ID。
///     中间使用逗号分隔。
///     忽略的类型不要写进表达式。
/// </summary>
public class SimpleTypeExpression
{
    internal readonly Dictionary<string, string> Equivalents;
    internal readonly HashSet<string> Excludes;
    internal readonly HashSet<string> Includes;
    internal readonly Dictionary<string, string> Unequals;

    internal SimpleTypeExpression()
    {
        Excludes = [];
        Includes = [];
        Equivalents = new Dictionary<string, string>();
        Unequals = new Dictionary<string, string>();
    }

    /// <summary>
    ///     当前表达式是否是空。
    /// </summary>
    public bool IsEmpty => Excludes.Count == 0
                           && Includes.Count == 0
                           && Equivalents.Count == 0
                           && Unequals.Count == 0;


    /// <summary>
    ///     只检查给定类型名是否符合包含和排除的表达式内容。
    /// </summary>
    public bool Exec(string typeName)
    {
        if (Includes.Count > 0 && !Includes.Contains(typeName) ||
            Excludes.Count > 0 && Excludes.Contains(typeName))
        {
            return false;
        }

        return true;
    }


    /// <summary>
    ///     使用表达式定义的值对给定类型名和类型值进行判断，
    ///     返回true时表示判断通过。
    ///     表达式在判断时，包含和不包含为一组，相等和不相等为一组，
    ///     组内是或的关系，组间是且的关系。
    /// </summary>
    public bool Exec(string typeName, string typeValue)
    {
        if (Includes.Count > 0 && !Includes.Contains(typeName) ||
            Excludes.Count > 0 && Excludes.Contains(typeName))
        {
            return false;
        }

        if (Equivalents.TryGetValue(typeName, out var eqval) && eqval != typeValue ||
            Unequals.TryGetValue(typeName, out var uneqval) && uneqval == typeValue)
        {
            return false;
        }

        return true;
    }


    /// <summary>
    ///     判断给定字典中的值是否满足表达式配置
    /// </summary>
    public bool Exec(IDictionary<string, string> nameValues)
    {
        foreach (string item in Includes)
        {
            if (!nameValues.ContainsKey(item))
            {
                return false;
            }
        }

        foreach (string item in Excludes)
        {
            if (nameValues.ContainsKey(item))
            {
                return false;
            }
        }

        foreach (KeyValuePair<string, string> item in Equivalents)
        {
            if (nameValues.TryGetValue(item.Key, out var eqval) && eqval != item.Value)
            {
                return false;
            }
        }

        foreach (KeyValuePair<string, string> item in Unequals)
        {
            if (nameValues.TryGetValue(item.Key, out var uneqval) && uneqval == item.Value)
            {
                return false;
            }
        }

        return true;
    }
}

/// <summary>
///     从表达式字符串中读取符合<see cref="SimpleTypeExpression" />定义的表达式内容。
/// </summary>
public class SimpleTypeExpressionParser
{
    private string _expression = string.Empty;
    private int _pos;
    private SimpleTypeExpression _simpleExprObj = new();

    private SimpleTypeExpressionParser()
    {
    }

    private void InitState(string expression)
    {
        _expression = expression;
        _pos = 0;
        _simpleExprObj = new SimpleTypeExpression();
    }


    private char CurrentChar()
    {
        return _pos >= _expression.Length ? '\0' : _expression[_pos];
    }


    private char NextChar()
    {
        ++_pos;
        return _pos < _expression.Length ? _expression[_pos] : '\0';
    }


    private char LookAheadChar()
    {
        int p = _pos + 1;
        return p < _expression.Length ? _expression[p] : '\0';
    }


    private void AddValue(string str, bool isExclude)
    {
        if (string.IsNullOrEmpty(str))
        {
            return;
        }

        if (isExclude)
        {
            _simpleExprObj.Excludes.Add(str);
        }
        else
        {
            _simpleExprObj.Includes.Add(str);
        }
    }


    private void AddEquality(string left, string right, bool isExclude)
    {
        if (string.IsNullOrEmpty(left) || string.IsNullOrEmpty(right))
        {
            return;
        }

        AddValue(left, isExclude);

        if (isExclude)
        {
            _simpleExprObj.Unequals.TryAdd(left, right);
        }
        else
        {
            _simpleExprObj.Equivalents.TryAdd(left, right);
        }
    }


    // 为了避免转义，标识符使用${}包裹。
    private string ReadIdentifier()
    {
        // 跳过 '$'
        _pos++;
        // 跳过 '{'
        char ch = NextChar();
        int start = _pos;

        // 一直读取到 '}'
        while (ch != '}')
        {
            // 如果遇到 '\0' 直接返回。
            if (ch == '\0')
            {
                throw new Exception($"未终结的标识符，起始位置：{start}。");
            }

            ch = NextChar();
        }

        string expr = _expression.Substring(start, _pos - start);

        // 跳过 '}'
        NextChar();

        return expr;
    }


    private bool Parse()
    {
        char ch = CurrentChar();

        if (ch == '\0')
        {
            return false;
        }

        // ^ 开头标识排除
        bool isExclude = false;
        if (ch == '^')
        {
            isExclude = true;
            ch = NextChar();
        }

        // 应当是 '$' 和 '{'
        if (ch != '$' || LookAheadChar() != '{')
        {
            return false;
        }

        string leftOperand = ReadIdentifier();

        // 遇到'='时，为值判断表达式
        if (CurrentChar() == '=')
        {
            // 跳过'='
            NextChar();
            string rightOperand = ReadIdentifier();
            AddEquality(leftOperand, rightOperand, isExclude);
        }
        else
        {
            AddValue(leftOperand, isExclude);
        }

        ch = CurrentChar();
        // 应当是',' 或 '\0'
        return ch == ',' || ch == '\0';
    }

    /// <summary>
    ///     读取符合<see cref="SimpleTypeExpression" />定义的表达式内容
    /// </summary>
    /// <param name="expression">表达式字符串</param>
    /// <returns>解析后的表达式</returns>
    public static SimpleTypeExpression Parse(string expression)
    {
        var parser = new SimpleTypeExpressionParser();
        parser.InitState(expression);

        // 一直读取到末尾
        while (parser.Parse())
        {
            char ch = parser.CurrentChar();
            // 跳过 ','
            if (ch == ',')
            {
                parser.NextChar();
            }

            if (ch == '\0')
            {
                break;
            }
        }

        return parser._simpleExprObj;
    }
}